package cn.larry.tools.weixin;

import cn.larry.tools.cons.Constants;
import cn.larry.tools.http.HttpTool;
import cn.larry.tools.string.StringTool;
import com.alibaba.fastjson.JSONObject;

import java.io.File;
import java.util.Calendar;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Larry
 * 2021/12/24 13:06
 * 微信相关接口工具
 *
 * @Version 2.0
 */
public class WeixinTool {

    /**
     * 获取token
     *
     * @param appid
     * @param secret
     * @return
     */
    public static String getPublicWeixinToken(String appid, String secret) {
        return getPublicWeixinToken2JSONObject(appid, secret).getString("access_token");
    }

    /**
     * 获取token
     *
     * @param appid
     * @param secret
     * @return JSONString（expires_in：有效期；access_token：token值）
     */
    public static JSONObject getPublicWeixinToken2JSONObject(String appid, String secret) {
        String getUrl = Constants.URL_WEIXIN_GET_TOKENURL + "?grant_type=client_credential&appid="
                + appid + "&secret=" + secret;
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }

    /**
     * 获取企业微信应用的token
     *
     * @param appid
     * @param secret
     * @return
     */
    public static String getTokenByQiye(String appid, String secret) {
        return getTokenByQiye2JSONObject(appid, secret).getString("access_token");
    }

    /**
     * 获取企业微信应用的token
     *
     * @param corpid
     * @param corpsecret
     * @return
     * @throws Exception
     */
    public static JSONObject getTokenByQiye2JSONObject(String corpid, String corpsecret) {
        String getUrl = Constants.URL_QIYEWEIXIN_GET_TOKENURL + "?corpid="
                + corpid
                + "&corpsecret=" + corpsecret;
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }

    /**
     * 获取微信公众号下用户的openid
     *
     * @param appid
     * @param code   微信用户临时授权code
     * @param secret
     * @return
     */
    public static String getPublicWeixinUserOpenid(String appid,
                                                   String code,
                                                   String secret) throws Exception {
        return getPublicWeixinUserOpenidByJSONObject(appid, code, secret).getString("openid");
    }

    /**
     * 获取微信公众号下用户的openid
     *
     * @param appid
     * @param code   微信用户临时授权code
     * @param secret
     * @return
     * @throws Exception
     */
    public static JSONObject getPublicWeixinUserOpenidByJSONObject(String appid,
                                                                   String code,
                                                                   String secret) throws Exception {
        if (StringTool.isBlank(appid))
            throw new Exception("appid is null");
        if (StringTool.isBlank(code))
            throw new Exception("code is null");
        if (StringTool.isBlank(secret))
            throw new Exception("secret is null");

        String url = Constants.URL_WEIXIN_GET_OPENID + "?appid=" + appid + "&secret=" + secret + "&code=" + code
                + "&grant_type=authorization_code";
        String body = HttpTool.get(url);

        return JSONObject.parseObject(body);
    }

    /**
     * 微信公众号新增永久素材
     * 【参考：https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html】
     *
     * @param file
     * @param type
     * @param title
     * @param introduction
     * @param access_token
     * @return JSON（media_id：素材ID; url：微信内打开的素材URL,注意反斜杠）
     * @throws Exception
     */
    public static JSONObject addPublicWeixinMaterial(File file, String type, String title, String introduction, String access_token) throws Exception {
        if (file == null)
            throw new Exception("file is null");

        String url = Constants.URL_PUBLIC_WEIXIN_ADD_MEDIA + "?access_token="
                + access_token + "&type=" + type;

        return HttpTool.addMaterial(file, type, title, introduction, url);
    }

    /**
     * 微信公众号删除永久素材
     *
     * @param mediaId
     * @param accessToken
     * @return
     * @throws Exception
     */
    public static boolean delPublicWeixinMaterial(String mediaId, String accessToken) throws Exception {

        if (StringTool.isBlank(mediaId))
            throw new Exception("mediaId is null");
        if (StringTool.isBlank(accessToken))
            throw new Exception("accessToken is null");

        boolean flag = false;

        String url = Constants.URL_PUBLIC_WEIXIN_DEL_MEDIA + "?access_token=" + accessToken;
        JSONObject reqJson = new JSONObject();
        reqJson.put("media_id", mediaId);
        String result = HttpTool.post(reqJson, url);
        JSONObject jsonObject = JSONObject.parseObject(result);
        String errcode = jsonObject.get("errcode") != null ? jsonObject.getString("errcode") : "";
        if ("0".equals(errcode))
            flag = true;

        return flag;
    }

    /**
     * 企业微信应用上传素材
     *
     * @param file
     * @param type
     * @param accessToken
     * @return
     */
    public static JSONObject addTemporaryMaterialFile(File file,
                                                      String type,
                                                      String accessToken,
                                                      String title,
                                                      String introduction) throws Exception {
        if (file == null)
            throw new Exception("file is null");
        if (StringTool.isBlank(type))
            throw new Exception("type is null");
        if (StringTool.isBlank(accessToken))
            throw new Exception("accessToken is null");

        String url = Constants.URL_QY_WEIXIN_ADD_MEDIA + "?access_token="
                + accessToken + "&type=" + type;

        return HttpTool.addMaterial(file, type, title, introduction, url);
    }


    /**
     * 微信公众号消息推送
     *
     * @param msgJson      消息模版内容
     * @param openId       用户openid
     * @param templateId   模版Id
     * @param goUrl        详情URL
     * @param isCompensate 是否重发
     * @param token        微信接口交互token
     * @return
     * @throws Exception
     */
    public static String sendPublicWeixinMsg(JSONObject msgJson,
                                             String openId,
                                             String templateId,
                                             String goUrl,
                                             boolean isCompensate,
                                             String token) throws Exception {
        if (msgJson == null || msgJson.size() < 1)
            throw new Exception("msgJson is null");
        if (StringTool.isBlank(openId))
            throw new Exception("accessToken is null");
        if (StringTool.isBlank(templateId))
            throw new Exception("templateId is null");
        if (StringTool.isBlank(token))
            throw new Exception("token is null");


        Set<String> keys = msgJson.keySet();
        String weixin_detail = "";
        for (String key : keys)
            weixin_detail += key + "|";
        weixin_detail = weixin_detail.substring(0, weixin_detail.length() - 1);

        String url = Constants.URL_WEIXIN_SEND_MESSAGE + "?access_token=" + token;
        JSONObject sendMsg = getPublicWeixinMsg(weixin_detail, msgJson, openId, templateId, goUrl);
        System.out.println(sendMsg);
        String respStr = HttpTool.post(sendMsg,
                url);
        if (isCompensate) {// 补偿
            JSONObject respJson = JSONObject.parseObject(respStr);
            String errcode = respJson.getString("errcode");
            if (!"0".equals(errcode)) {
                TimeUnit.SECONDS.sleep(5);
                sendPublicWeixinMsg(msgJson, openId, templateId, goUrl, false, token);
            }
        }
        return respStr;
    }


    /**
     * 组微信公众号消息发送时的请求JSONObject
     *
     * @param weixinDetail
     * @param magData
     * @param openid
     * @param templateId
     * @param goUrl
     * @return
     * @throws Exception
     */
    @Deprecated
    private static JSONObject getPublicWeixinMsg(String weixinDetail,
                                                 String magData,
                                                 String openid,
                                                 String templateId,
                                                 String goUrl) throws Exception {
        JSONObject jsonObject = new JSONObject();
        JSONObject jsonData = new JSONObject();
        JSONObject paramJson = new JSONObject();
        try {
            paramJson = JSONObject.parseObject(magData);
        } catch (Exception e) {
            throw new Exception("magData parsing exception");
        }

        String[] templateSplit = weixinDetail.split("\\|");
        for (int i = 0; i < templateSplit.length; i++) {
            try {
                String key = templateSplit[i];
                String vc = paramJson.getString(key);
                if (null != vc) {
                    String[] strs = vc.split("\\|");
                    String value = strs[0];
                    JSONObject jsonDataSon = new JSONObject();
                    jsonDataSon.put("value", value.replace("\\n", "\n"));// 防止“\\n”，微信只认“\n”
                    if (strs.length > 1) {
                        String color = strs[1];
                        jsonDataSon.put("color", color);// 默认是黑色
                    }
                    jsonData.put(key, jsonDataSon);
                }
            } catch (Exception e) {
                throw new Exception("sendMsg Encapsulation exception");
            }
        }

        jsonObject.put("touser", openid);
        jsonObject.put("template_id", templateId);
        jsonObject.put("url", goUrl);
        jsonObject.put("magData", jsonData);
        return jsonObject;
    }

    /**
     * 组微信公众号消息发送时的请求JSONObject
     *
     * @param weixinDetail
     * @param paramJson
     * @param openid
     * @param templateId
     * @param goUrl
     * @return
     * @throws Exception
     */
    private static JSONObject getPublicWeixinMsg(String weixinDetail,
                                                 JSONObject paramJson,
                                                 String openid,
                                                 String templateId,
                                                 String goUrl) throws Exception {
        JSONObject jsonObject = new JSONObject();
        JSONObject jsonData = new JSONObject();

        String[] templateSplit = weixinDetail.split("\\|");
        for (int i = 0; i < templateSplit.length; i++) {
            try {
                String key = templateSplit[i];
                String vc = paramJson.getString(key);
                if (null != vc) {
                    String[] strs = vc.split("\\|");
                    String value = strs[0];
                    JSONObject jsonDataSon = new JSONObject();
                    jsonDataSon.put("value", value.replace("\\n", "\n"));// 防止“\\n”，微信只认“\n”
                    if (strs.length > 1) {
                        String color = strs[1];
                        jsonDataSon.put("color", color);// 默认是黑色
                    }
                    jsonData.put(key, jsonDataSon);
                }
            } catch (Exception e) {
                throw new Exception("sendMsg Encapsulation exception");
            }
        }

        jsonObject.put("touser", openid);
        jsonObject.put("template_id", templateId);
        if (StringTool.isNotBlank(goUrl))
            jsonObject.put("url", goUrl);
        jsonObject.put("data", jsonData);
        return jsonObject;
    }

    /**
     * 获取微信小程序的 URL Link
     * （小于31天的有效日期，URL Link数量为无限）
     * （参考：https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-link.html）
     *
     * @param access_token
     * @param applet_path
     * @param path_query
     * @param is_expire       生成的 URL Link 类型，到期失效：true，永久有效：false
     * @param expire_type     小程序 URL Link 失效类型，失效时间：0，失效间隔天数：1
     * @param expire_interval 到期失效的URL Link的失效间隔天数。生成的到期失效URL Link在该间隔时间到达前有效。最长间隔天数为365天。expire_type 为 1 必填
     * @return
     * @throws Exception
     */
    public static String getAppletUrllink(String access_token, String applet_path, String path_query, boolean is_expire, Object expire_type, Object expire_interval) throws Exception {
        String url = Constants.URL_WEIXIN_GET_APPLETURLLINK + "?access_token=" + access_token;

        JSONObject json = new JSONObject();
        json.put("path", applet_path);
        if (StringTool.isNotBlank(path_query))
            json.put("query", path_query);
        json.put("is_expire", is_expire);
        if (expire_type != null)
            json.put("expire_type", expire_type);
        if (expire_interval != null)
            json.put("expire_interval", expire_interval);
        JSONObject jsonObject = JSONObject.parseObject(HttpTool.post(json, url));

        return jsonObject.getString("url_link").replace("\\", "");
    }

    /**
     * 小程序登录凭证：根据登录凭证code获取其他信息
     *
     * @param appid
     * @param secret
     * @param code
     * @return
     */
    public static JSONObject getAppletCode2Session(String appid, String secret, String code) {
        String getUrl = Constants.URL_WEIXINAPPLET_GET_JSCODE2SESSION + "?appid="
                + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }


    // ------------------------ 微信开放平台相关接口  start
    // 参考文档：https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Authorized_API_call_UnionID.html

    /**
     * 通过 code 获取 access_token
     *
     * @param appid
     * @param secret
     * @param code
     * @return
     */
    public static JSONObject weixinopenGetAccessToken(String appid, String secret, String code) {
        String getUrl = Constants.URL_WEIXINOPEN_GET_ACCESSTOKEN + "?appid="
                + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }

    /**
     * 刷新或续期 access_token 使用
     *
     * @param appid
     * @param refresh_token
     * @return
     */
    public static JSONObject weixinopenGetRefreshToken(String appid, String refresh_token) {
        String getUrl = Constants.URL_WEIXINOPEN_GET_REFRESHTOKEN + "?appid="
                + appid + "&grant_type=refresh_token&refresh_token=" + refresh_token;
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }

    /**
     * 检验授权凭证（access_token）是否有效
     *
     * @param openid
     * @param access_token
     * @return
     */
    public static JSONObject weixinopenGetVerifyToken(String openid, String access_token) {
        String getUrl = Constants.URL_WEIXINOPEN_GET_VERIFYTOKEN + "?access_token="
                + access_token + "&openid=" + openid;
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }

    /**
     * 使用微信用户openid获取unionid等其他微信用户信息
     *
     * @param access_token
     * @param openid
     * @return
     */
    public static JSONObject weixinopenGetUserinfo(String access_token, String openid) {
        String getUrl = Constants.URL_WEIXINOPEN_GET_USERINFO + "?access_token="
                + access_token + "&openid=" + openid;
        return JSONObject.parseObject(HttpTool.get(getUrl));
    }


    // ------------------------ 微信开放平台相关接口  end

}
